package com.thread.chapter2;

import cn.hutool.core.thread.ThreadUtil;
import lombok.Data;

@Data
public class Demo227 extends Thread {

    private String execMethod = new String();
    private Demo227 task;

    public Demo227(Demo227 task, String execMethod) {
        this.task = task;
        this.execMethod = execMethod;
    }

    public void syncMethodA() {
        synchronized (execMethod) {
            System.out.println("syncMethodA 开始:" + currentThread().getName());
            ThreadUtil.sleep(2000);
            System.out.println("syncMethodA 结束:" + currentThread().getName());
        }
    }

    public synchronized void syncMethodB() {
        System.out.println("syncMethodB 开始:" + currentThread().getName());
        System.out.println("syncMethodB 结束:" + currentThread().getName());
    }

    public void syncMethodC() {
        synchronized (execMethod) {
            System.out.println("syncMethodC 开始:" + currentThread().getName());
            ThreadUtil.sleep(2000);
            System.out.println("syncMethodC 结束:" + currentThread().getName());
        }
    }

    public void syncMethodD() {
        synchronized (new String()) {
            System.out.println("syncMethodD 开始:" + currentThread().getName());
            System.out.println("syncMethodD 结束:" + currentThread().getName());
        }
    }

    @Override
    public void run() {
        super.run();
        if ("A".equals(execMethod)) {
            task.syncMethodA();
        } else if ("B".equals(execMethod)) {
            task.syncMethodB();
        } else if ("C".equals(execMethod)) {
            task.syncMethodC();
        } else if ("D".equals(execMethod)) {
            task.syncMethodD();
        }
    }

   /* 多个线程调用同一对象的synchronized同步方法或synchronized(this)同步代码块时,调用效果就是顺序执行,也就是同步的,阻塞的
    锁非this对象有一定的优点：如果一个类中有很多synchronized方法,这时虽能同步,但会受到阻塞,影响运行效率。
    但使用锁非this对象,则synchronized(非this)代码块程序与同步方法是异步的,不与其它锁this同步方法争抢this锁。

    此示例中: A和C用同一个锁对象,则是同步执行,先执行A再执行C
    而B是同步方法,和A、C是异步执行的
    C和D是不同的锁对象即不同的对象监视器,因此是异步执行
    */

    public static void main(String[] args) {
        Demo227 task = new Demo227();
        Demo227 a = new Demo227(task, "A");
        a.start();
        ThreadUtil.sleep(1000);
        Demo227 b = new Demo227(task, "B");
        b.start();
        Demo227 c = new Demo227(task, "C");
        c.start();
        ThreadUtil.sleep(1000);
        Demo227 d = new Demo227(task, "D");
        d.start();
    }
}
